#include "test_utilities.h"
#include <stdlib.h>
#include "../list.h"

/** Function to be used for copying an int into the list */
static ListElement copyInt(ListElement n) {
	if (!n) {
		return NULL;
	}
	int* copy = malloc(sizeof(*copy));
	if (!copy) {
		return NULL;
	}
	*copy = *(int*)n;
	return copy;
}

/** Function to be used by the list for freeing elements */
static void freeInt(ListElement n) {
	free(n);
}

/** Function to be used by the list for freeing elements */
static int compareInts(ListElement n1, ListElement n2) {
	return  *(int*)n1 - *(int*)n2;
}

/** Function to be used by the list for filtering elements */
static bool isPositive(ListElement n) {
    return *(int*)n > 0;
}

bool testListExample() {
	int one = 1;
	int minusOne = -1;
	int seven = 7;

	List list = listCreate(copyInt, freeInt);
	ASSERT_TEST(list != NULL);
	ASSERT_TEST(listGetSize(list) == 0);
	ASSERT_TEST(listGetCurrent(list) == NULL);
	ASSERT_TEST(listGetFirst(list) == NULL);
	ASSERT_TEST(listInsertFirst(list, &one) == LIST_SUCCESS);
	ASSERT_TEST(listInsertFirst(list, &minusOne) == LIST_SUCCESS);
	ASSERT_TEST(listGetSize(list) == 2);

	ASSERT_TEST(*(int*)listGetFirst(list) == -1);
	ASSERT_TEST(*(int*)listGetNext(list) == 1);
	ASSERT_TEST(listGetNext(list) == NULL);

	List copy = listCopy(list);
	ASSERT_TEST(listGetFirst(copy) != NULL);
	ASSERT_TEST(listRemoveCurrent(copy) == LIST_SUCCESS);

	ASSERT_TEST(*(int*)listGetFirst(list) == -1);
	ASSERT_TEST(*(int*)listGetNext(list) == 1);
	ASSERT_TEST(listGetNext(list) == NULL);

	ASSERT_TEST(*(int*)listGetFirst(copy) == 1);
	ASSERT_TEST(listGetNext(copy) == NULL);

	ASSERT_TEST(listClear(copy) == LIST_SUCCESS);
	ASSERT_TEST(listGetSize(copy) == 0);
	
	listDestroy(copy);

	ASSERT_TEST(listInsertLast(list, &seven) == LIST_SUCCESS);
	ASSERT_TEST(listGetSize(list) == 3);

	copy = listFilter(list, isPositive);
	ASSERT_TEST(copy != NULL);
	ASSERT_TEST(listGetSize(copy) == 2);
	ASSERT_TEST(*(int*)listGetFirst(copy) == 1);
	ASSERT_TEST(*(int*)listGetNext(copy) == 7);
	ASSERT_TEST(listGetNext(copy) == NULL);

    ASSERT_TEST(listInsertLast(list, &minusOne) == LIST_SUCCESS);
	ASSERT_TEST(*(int*)listGetFirst(list) == -1);
	ASSERT_TEST(*(int*)listGetNext(list) == 1);
	ASSERT_TEST(*(int*)listGetNext(list) == 7);
	ASSERT_TEST(*(int*)listGetNext(list) == -1);
	ASSERT_TEST(listGetNext(list) == NULL);
    ASSERT_TEST(listSort(list, compareInts) == LIST_SUCCESS);
	ASSERT_TEST(*(int*)listGetFirst(list) == -1);
	ASSERT_TEST(*(int*)listGetNext(list) == -1);
	ASSERT_TEST(*(int*)listGetNext(list) == 1);
	ASSERT_TEST(*(int*)listGetNext(list) == 7);
	ASSERT_TEST(listGetNext(list) == NULL);
    	

	listDestroy(list);
	listDestroy(copy);

	return true;
}

int main() {
	RUN_TEST(testListExample);
	return 0;
}
